#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <sstream>
#include <fstream>
#include "Log.hpp"

static const std::string sep = "\r\n";
static const std::string header_sep = ": ";
static const std::string wwwroot = "wwwroot";      // web根目录
static const std::string homepage = "index.html";  // 当访问的是/时，默认拼接上index.html
static const std::string httpversion = "HTTP/1.0"; // http版本
static const std::string space = " ";
static const std::string filesuffixsep = "."; // 后缀分隔符
static const std::string args_sep = "?";      // url和参数的分割符 www.baidu.com/s?wd=xxx&passwd=xxx

class HttpRequest;
class HttpResponse;

using func_t = std::function<std::shared_ptr<HttpResponse>(std::shared_ptr<HttpRequest>)>;

class HttpRequest
{
private:
  std::string ParseLine(std::string &reqstr)
  {
    if (reqstr.empty())
      return reqstr;
    auto pos = reqstr.find(sep);
    if (pos == std::string::npos)
      return std::string();

    std::string line = reqstr.substr(0, pos); // 获取一行
    reqstr.erase(0, pos + sep.size());        // 将提取到的一行移除
    return line.empty() ? sep : line;         // 如果截取到的行为空，证明此时读取到的是空行，我们返回\r\n
  }
  bool ParseHeaderHelper(const std::string &line, std::string *k, std::string *v)
  {
    auto pos = line.find(header_sep);
    if (pos == std::string::npos)
      return false;
    *k = line.substr(0, pos);
    *v = line.substr(pos + header_sep.size());
    return true;
  }

public:
  HttpRequest() : _blank_line(sep), _path(wwwroot)
  {
  }
  void Serialize() {} // 无需实现，因为对请求序列化是客户端要考虑的
  void Deserialize(std::string &reqstr)
  {
    _req_line = ParseLine(reqstr);
    while (true)
    {
      std::string line = ParseLine(reqstr);
      if (line.empty())
        break;
      else if (line == sep) // 说明此时报头已经读完，该读正文了
      {
        _req_text = reqstr;
        break;
      }
      else
      {
        _req_header.emplace_back(line);
      }
    }
    ParseReqLine();
    ParseHeader();
  }
  void Print()
  {
    std::cout << "===" << _req_line << std::endl;
    for (auto &header : _req_header)
    {
      std::cout << "***" << header << std::endl;
    }
    std::cout << _blank_line;
    std::cout << _req_text << std::endl;

    std::cout << "method ### " << _method << std::endl;
    std::cout << "url ### " << _url << std::endl;
    std::cout << "path ### " << _path << std::endl;
    std::cout << "httpverion ### " << _version << std::endl;
    for (auto &header : _headers)
    {
      std::cout << "@@@" << header.first << " - " << header.second << std::endl;
    }
  }
  bool ParseReqLine()
  {
    if (_req_line.empty())
      return false;

    std::stringstream ss(_req_line);
    ss >> _method >> _url >> _version; // stringstream自动过滤空格

    // /index.html?use=zhangsan&passwd=123456 提取参数
    if (strcasecmp("get", _method.c_str()) == 0) // strcasecmp忽略大小写匹配get
    {
      auto pos = _url.find(args_sep);
      if (pos != std::string::npos)
      {
        LOG(INFO, "change begin, url: %s\n", _url.c_str());
        _args = _url.substr(pos + args_sep.size());
        _url.resize(pos);
        LOG(INFO, "change done, url: %s, _args: %s\n", _url.c_str(), _args.c_str());
      }
    }

    _path += _url;

    LOG(DEBUG, "url: %s", _url.c_str());
    // 判断一下请求的是不是/，web根目录wwwroot/
    if (_path[_path.size() - 1] == '/')
    {
      _path += homepage;
    }

    auto pos = _path.rfind(filesuffixsep);
    if (pos == std::string::npos)
    {
      _suffix = ".unKnown";
    }
    else
    {
      _suffix = _path.substr(pos);
    }
    LOG(INFO, "client want get %s, _suffix :%s", _path.c_str(), _suffix.c_str());
    return true;
  }
  bool ParseHeader()
  {
    for (auto &header : _req_header)
    {
      std::string k;
      std::string v;
      if (ParseHeaderHelper(header, &k, &v))
      {
        _headers.insert(std::make_pair(k, v));
      }
    }
    return true;
  }
  std::string Path()
  {
    return _path;
  }
  std::string Suffix()
  {
    return _suffix;
  }
  bool IsExec() // 判断参数和正文是否不为空，即需要我们处理
  {
    return !_args.empty() || !_req_text.empty();
  }
  std::string Args()
  {
    return _args;
  }
  std::string Text()
  {
    return _req_text;
  }
  std::string Method()
  {
    return _method;
  }
  ~HttpRequest() {}

private:
  // 原始协议内容
  std::string _req_line;                // 请求行
  std::vector<std::string> _req_header; // 请求报头
  std::string _blank_line;              // 空行
  std::string _req_text;                // 请求正文

  // 期望解析的结果
  std::string _method;                                   // 请求方法
  std::string _url;                                      // url
  std::string _args;                                     // url中的参数
  std::string _path;                                     // 真实的路径
  std::string _suffix;                                   // 文件后缀
  std::string _version;                                  // http版本
  std::unordered_map<std::string, std::string> _headers; // 请求报头kv
};

class HttpResponse
{
public:
  HttpResponse() : _version(httpversion), _blank_line(sep)
  {
  }
  void AddStatusLine(int code, const std::string &desc)
  {
    _code = code;
    _desc = desc; // TODO
  }
  void AddHeader(const std::string &k, const std::string &v)
  {
    LOG(DEBUG, "AddHeader: %s->%s", k.c_str(), v.c_str());
    _headers[k] = v;
  }
  void AddText(const std::string &text)
  {
    _resp_text = text;
  }
  std::string Serialize()
  {
    _status_line = _version + space + std::to_string(_code) + space + _desc + sep;
    for (auto &header : _headers)
    {
      _resp_header.emplace_back(header.first + header_sep + header.second + sep);
    }
    // 序列化
    std::string respstr = _status_line;
    for (auto &header : _resp_header)
    {
      respstr += header;
    }
    respstr += _blank_line;
    respstr += _resp_text;
    return respstr;
  }
  void Deserialize() {}
  ~HttpResponse() {}

private:
  // 构建应答的必要字段
  std::string _version;                                  // http版本
  int _code;                                             // 状态码
  std::string _desc;                                     // 状态描述
  std::unordered_map<std::string, std::string> _headers; // 响应报头kv

  // 应答的结构化字段
  std::string _status_line;              // 状态行
  std::vector<std::string> _resp_header; // 响应报头
  std::string _blank_line;               // 空行
  std::string _resp_text;                // 响应正文
};

class Factory
{
public:
  static std::shared_ptr<HttpRequest> BuildHttpRequest()
  {
    return std::make_shared<HttpRequest>();
  }
  static std::shared_ptr<HttpResponse> BuildHttpResponose()
  {
    return std::make_shared<HttpResponse>();
  }
};

class HttpServer
{
public:
  HttpServer()
  {
    _mime_type.insert(std::make_pair(".html", "text/html"));
    _mime_type.insert(std::make_pair(".css", "text/css"));
    _mime_type.insert(std::make_pair(".js", "application/x-javascript"));
    _mime_type.insert(std::make_pair(".png", "image/png"));
    _mime_type.insert(std::make_pair(".jpg", "image/jpeg"));
    _mime_type.insert(std::make_pair(".unknown", "text/html"));

    _code_to_desc.insert(std::make_pair(100, "Continue"));
    _code_to_desc.insert(std::make_pair(200, "OK"));
    _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
    _code_to_desc.insert(std::make_pair(302, "Found"));
    _code_to_desc.insert(std::make_pair(404, "Not Found"));
    _code_to_desc.insert(std::make_pair(500, "Internal Server Error"));
  }
  void AddHandler(const std::string functionname, func_t f)
  {
    std::string key = wwwroot + functionname; // wwwroot/login
    _funcs[key] = f;
  }
  std::string ReadFileContent(const std::string &path, int *size)
  {
    // 要按照二进制打开
    std::ifstream in(path, std::ios::binary);
    if (!in.is_open())
    {
      return std::string();
    }
    in.seekg(0, in.end);       // 将文件指针定位到结尾
    int filesize = in.tellg(); // 获取当前文件指针位置，即获取文件长度
    in.seekg(0, in.beg);       // 将文件指针定位到开始

    std::string content;
    content.resize(filesize);
    in.read((char *)content.c_str(), filesize);
    in.close();
    *size = filesize;
    return content;
  }
  std::string HandlerHttpRequest(std::string req)
  {
#ifdef TEST
    std::cout << "-----------------------------------" << std::endl;
    std::cout << req;

    std::string response = "HTTP/1.0 200 OK\r\n";
    response += "\r\n";
    response += "<html><body><h1>hello world</h1></body></html>";
    return response;
#else
    auto request = Factory::BuildHttpRequest();
    request->Deserialize(req);

    // std::string newurl = "https://www.baidu.com/";
    // std::string newurl = "http://116.204.13.111:8080/3.html";
    // int code = 0;
    // if (request->Path() == "wwwroot/redir")
    // {
    //   code = 301;
    //   response->AddStatusLine(code, _code_to_desc[code]);
    //   response->AddHeader("Location", newurl);
    // }
    if (request->IsExec()) // 证明url或正文有参数
    {
      auto response = _funcs[request->Path()](request);
      return response->Serialize();
    }
    else
    {
      auto response = Factory::BuildHttpResponose();

      int code = 200;
      int contentsize = 0;
      std::string text = ReadFileContent(request->Path(), &contentsize);
      if (text.empty())
      {
        code = 404;
        response->AddStatusLine(code, _code_to_desc[code]);
        std::string text404 = ReadFileContent("wwwroot/404.html", &contentsize);
        response->AddHeader("Content-Length", std::to_string(contentsize));
        response->AddHeader("Content-Type", _mime_type[".html"]);
        response->AddText(text404);
      }
      else
      {
        std::string suffix = request->Suffix();
        response->AddStatusLine(code, _code_to_desc[code]);
        response->AddHeader("Content-Length", std::to_string(contentsize));
        response->AddText(text);
        response->AddHeader("Content-Type", _mime_type[suffix]);
      }
      return response->Serialize();
    }

    // http协议已经给我们规定好了不同文件后缀对应的Content-Type

    // response->AddHeader("Location", "https://www.qq.com/");
    // response->AddHeader("Location", "http://8.137.19.140:8888/image/1.png");

#endif
  }

  ~HttpServer() {}

private:
  std::unordered_map<std::string, std::string> _mime_type; // 文件后缀和Content-Type的对照表
  std::unordered_map<int, std::string> _code_to_desc;      // 状态码和状态描述的对照表
  std::unordered_map<std::string, func_t> _funcs;          // 不同url所对应的服务表  www.baidu.com/s   比如"s"就对应着一种服务
};